﻿using System;
using System.Linq;
using SD.LLBLGen.Pro.ORMSupportClasses;
using SD.LLBLGen.Pro.QuerySpec;
using SD.LLBLGen.Pro.QuerySpec.Adapter;
using VNet.VisiSuite.BusinessLogic.BusinessException;
using VNet.VisiSuite.Common.Helper;
using VNet.VisiSuite.Common.Resource;
using VNet.VisiSuite.Dal.DatabaseSpecific;
using VNet.VisiSuite.Dal.EntityClasses;
using VNet.VisiSuite.Dal.FactoryClasses;
using VNet.VisiSuite.Dal.HelperClasses;
using VNet.VisiSuite.Service.Contact.Enum;
using VNet.VisiSuite.Service.Contact.Message.Item;
using VNet.VisiSuite.Service.Contact.Message.Base;
using System.Collections.Generic;
using VNet.VisiSuite.Common.Logger;

namespace VNet.VisiSuite.BusinessLogic
{
    public class UserLoginUtil
    {
        private QueryFactory _queryFactory = new QueryFactory();

        public DeleteDataResponse DeleteUser(DeleteDataRequest request)
        {
            using (var adapter = new DataAccessAdapter())
            {
                try
                {
                    var user_query =
                        _queryFactory.UserLogin.Where(
                            (UserLoginFields.UserLoginId != request.DataId).And(
                                (UserLoginFields.CreatedBy == request.DataId).Or(UserLoginFields.LastUpdatedBy ==
                                                                                 request.DataId)))
                            .Include(UserLoginFields.UserLoginId)
                            .Select(UserLoginFields.UserLoginId);
                    var user = adapter.FetchQuery(user_query);
                    if (user != null && user.Count > 0)
                        return new DeleteDataResponse
                        {
                            Success = false,
                            Error = new ServiceError { Description = ErrorMessages.ProductInUsed + "User Table" }
                        };

                    var user_history_query =
                        _queryFactory.UserLoginHistory.Where(UserLoginHistoryFields.UserLoginId == request.DataId)
                            .Include(UserLoginHistoryFields.UserLoginId)
                            .Select(UserLoginHistoryFields.UserLoginId);
                    var user_history = adapter.FetchQuery(user_history_query);
                    if (user_history != null && user_history.Count > 0)
                        return new DeleteDataResponse
                        {
                            Success = false,
                            Error = new ServiceError { Description = ErrorMessages.ProductInUsed + "UserHistory Table" }
                        };


                    var rollup_definition_query =
                        _queryFactory.RollupDefinition.Where(
                            (RollupDefinitionFields.CreatedBy == request.DataId).Or(
                                RollupDefinitionFields.LastUpdatedBy == request.DataId))
                            .Include(RollupDefinitionFields.RollupDefinitionId)
                            .Select(RollupDefinitionFields.RollupDefinitionId);
                    var rollup_definition = adapter.FetchQuery(rollup_definition_query);
                    if (rollup_definition != null && rollup_definition.Count > 0)
                        return new DeleteDataResponse
                        {
                            Success = false,
                            Error =
                                new ServiceError { Description = ErrorMessages.ProductInUsed + "RollupDefinition Table" }
                        };

                    var reason_code_query =
                        _queryFactory.ReasonCode.Where(
                            (ReasonCodeFields.CreatedBy == request.DataId).Or(ReasonCodeFields.LastUpdatedBy ==
                                                                              request.DataId))
                            .Include(ReasonCodeFields.ReasonCodeId)
                            .Select(ReasonCodeFields.ReasonCodeId);
                    var reason_code = adapter.FetchQuery(reason_code_query);
                    if (reason_code != null && reason_code.Count > 0)
                        return new DeleteDataResponse
                        {
                            Success = false,
                            Error = new ServiceError { Description = ErrorMessages.ProductInUsed + "ReasonCode Table" }
                        };

                    var production_plan_scheduled_downtime_query =
                        _queryFactory.ProductionPlanScheduledDowntime.Where(
                            (ProductionPlanScheduledDowntimeFields.CreatedBy == request.DataId).Or(
                                ProductionPlanScheduledDowntimeFields.LastUpdatedBy == request.DataId))
                            .Include(ProductionPlanScheduledDowntimeFields.ProductionPlanScheduledDowntimeId)
                            .Select(ProductionPlanScheduledDowntimeFields.ProductionPlanScheduledDowntimeId);
                    var production_plan_scheduled_downtime = adapter.FetchQuery(production_plan_scheduled_downtime_query);
                    if (production_plan_scheduled_downtime != null && production_plan_scheduled_downtime.Count > 0)
                        return new DeleteDataResponse
                        {
                            Success = false,
                            Error =
                                new ServiceError { Description = ErrorMessages.ProductInUsed + "ScheduleDowntime Table" }
                        };

                    var production_plan_query =
                        _queryFactory.ProductionPlan.Where(
                            (ProductionPlanFields.CreatedBy == request.DataId).Or(ProductionPlanFields.LastUpdatedBy ==
                                                                                  request.DataId))
                            .Include(ProductionPlanFields.ProductionPlanId)
                            .Select(ProductionPlanFields.ProductionPlanId);
                    var production_plan = adapter.FetchQuery(production_plan_query);
                    if (production_plan != null && production_plan.Count > 0)
                        return new DeleteDataResponse
                        {
                            Success = false,
                            Error =
                                new ServiceError { Description = ErrorMessages.ProductInUsed + "ProductionPlan Table" }
                        };

                    var product_query =
                        _queryFactory.Product.Where(
                            (ProductFields.CreatedBy == request.DataId).Or(ProductFields.LastUpdatedBy == request.DataId))
                            .Include(ProductFields.ProductId)
                            .Select(ProductFields.ProductId);
                    var product = adapter.FetchQuery(product_query);
                    if (product != null && product.Count > 0)
                        return new DeleteDataResponse
                        {
                            Success = false,
                            Error = new ServiceError { Description = ErrorMessages.ProductInUsed + "Product Table" }
                        };

                    var plant_query =
                        _queryFactory.Plant.Where(
                            (PlantFields.CreatedBy == request.DataId).Or(PlantFields.LastUpdatedBy == request.DataId))
                            .Include(PlantFields.PlantId)
                            .Select(PlantFields.PlantId);
                    var plant = adapter.FetchQuery(plant_query);
                    if (plant != null && plant.Count > 0)
                        return new DeleteDataResponse
                        {
                            Success = false,
                            Error = new ServiceError { Description = ErrorMessages.ProductInUsed + "Plant Table" }
                        };

                    var launch_application_query =
                        _queryFactory.LaunchApplication.Where(
                            (LaunchApplicationFields.CreatedBy == request.DataId).Or(
                                LaunchApplicationFields.LastUpdatedBy == request.DataId))
                            .Include(LaunchApplicationFields.LaunchApplicationId)
                            .Select(LaunchApplicationFields.LaunchApplicationId);
                    var launch_application = adapter.FetchQuery(launch_application_query);
                    if (launch_application != null && launch_application.Count > 0)
                        return new DeleteDataResponse
                        {
                            Success = false,
                            Error =
                                new ServiceError { Description = ErrorMessages.ProductInUsed + "LaunchApplication Table" }
                        };

                    var downtime_button_query =
                        _queryFactory.DowntimeButton.Where(
                            (DowntimeButtonFields.CreatedBy == request.DataId).Or(DowntimeButtonFields.LastUpdatedBy ==
                                                                                  request.DataId))
                            .Include(DowntimeButtonFields.DowntimeButtonId)
                            .Select(DowntimeButtonFields.DowntimeButtonId);
                    var downtime_button = adapter.FetchQuery(downtime_button_query);
                    if (downtime_button != null && downtime_button.Count > 0)
                        return new DeleteDataResponse
                        {
                            Success = false,
                            Error =
                                new ServiceError { Description = ErrorMessages.ProductInUsed + "DowntimeButton Table" }
                        };

                    var cell_alarm_setting_query =
                        _queryFactory.CellAlarmSetting.Where(
                            (CellAlarmSettingFields.CreatedBy == request.DataId).Or(
                                CellAlarmSettingFields.LastUpdatedBy == request.DataId))
                            .Include(CellAlarmSettingFields.CellAlarmSettingId)
                            .Select(CellAlarmSettingFields.CellAlarmSettingId);
                    var cell_alarm_setting = adapter.FetchQuery(cell_alarm_setting_query);
                    if (cell_alarm_setting != null && cell_alarm_setting.Count > 0)
                        return new DeleteDataResponse
                        {
                            Success = false,
                            Error =
                                new ServiceError { Description = ErrorMessages.ProductInUsed + "CellAlarmSetting Table" }
                        };

                    var cell_query =
                        _queryFactory.Cell.Where(
                            (CellFields.CreatedBy == request.DataId).Or(CellFields.LastUpdatedBy == request.DataId))
                            .Include(CellFields.CellId)
                            .Select(CellFields.CellId);
                    var cell = adapter.FetchQuery(cell_query);
                    if (cell != null && cell.Count > 0)
                        return new DeleteDataResponse
                        {
                            Success = false,
                            Error = new ServiceError { Description = ErrorMessages.ProductInUsed + "CellId Table" }
                        };

                    var area_shift_query =
                        _queryFactory.AreaShift.Where(
                            (AreaShiftFields.CreatedBy == request.DataId).Or(AreaShiftFields.LastUpdatedBy ==
                                                                             request.DataId))
                            .Include(AreaShiftFields.AreaShiftId)
                            .Select(AreaShiftFields.AreaShiftId);
                    var area_shift = adapter.FetchQuery(area_shift_query);
                    if (area_shift != null && area_shift.Count > 0)
                        return new DeleteDataResponse
                        {
                            Success = false,
                            Error = new ServiceError { Description = ErrorMessages.ProductInUsed + "AreaShift Table" }
                        };

                    var area_query =
                        _queryFactory.Area.Where(
                            (AreaFields.CreatedBy == request.DataId).Or(AreaFields.LastUpdatedBy == request.DataId))
                            .Include(AreaFields.AreaId)
                            .Select(AreaFields.AreaId);
                    var area = adapter.FetchQuery(area_query);
                    if (area != null && area.Count > 0)
                        return new DeleteDataResponse
                        {
                            Success = false,
                            Error = new ServiceError { Description = ErrorMessages.ProductInUsed + "AreaFields Table" }
                        };

                    var alarm_setting_query =
                        _queryFactory.AlarmSetting.Where(
                            (AlarmSettingFields.CreatedBy == request.DataId).Or(AlarmSettingFields.LastUpdatedBy ==
                                                                                request.DataId))
                            .Include(AlarmSettingFields.AlarmSettingId)
                            .Select(AlarmSettingFields.AlarmSettingId);
                    var alarm_setting = adapter.FetchQuery(alarm_setting_query);
                    if (alarm_setting != null && alarm_setting.Count > 0)
                        return new DeleteDataResponse
                        {
                            Success = false,
                            Error = new ServiceError { Description = ErrorMessages.ProductInUsed + "AlarmSetting Table" }
                        };


                    var query2 = _queryFactory.UserLogin.Where(UserLoginFields.UserLoginId == request.DataId);
                    var user_entity = adapter.FetchFirst(query2);
                    if (user_entity == null)
                        return new DeleteDataResponse { Error = BusinessLogicError.UserDoesNotExist, Success = false };

                    if (!adapter.DeleteEntity(user_entity))
                        return new DeleteDataResponse { Error = BusinessLogicError.DeleteUsertFailed, Success = false };

                    return new DeleteDataResponse { Success = true, DataId = request.DataId };
                }
                catch (Exception exp)
                {
                    return new DeleteDataResponse { Success = false, Error = BusinessLogicError.DeleteUsertFailed };
                }
            }
        }

        public GetDataResponse<IList<UserLoginItem>> GetUsers(ServiceBaseRequest request)
        {
            using (var adapter = new DataAccessAdapter())
            {
                try
                {
                    EntityQuery<UserLoginEntity> query = _queryFactory.UserLogin.WithPath(UserLoginEntity.PrefetchPathUserLogin, UserLoginEntity.PrefetchPathUserLogin1);

                    EntityCollection<UserLoginEntity> entities;

                    entities = (EntityCollection<UserLoginEntity>)adapter.FetchQuery(query);
                    if (entities == null)
                        return new GetDataResponse<IList<UserLoginItem>> { Success = false, Error = BusinessLogicError.GetUserFailed };

                    var result = new List<UserLoginItem>();
                    foreach (var entity in entities)
                    {
                        var user = new UserLoginItem
                        {
                            UserLoginId = entity.UserLoginId,
                            FirstName = entity.FirstName,
                            LastName = entity.LastName,
                            Email = entity.Email,
                            Enabled = entity.Enabled,
                            Login = entity.Login,
                        };
                        if (entity.UserLogin != null)
                        {
                            user.CreatedDate = entity.CreatedDate;
                            user.LastUpdatedDate = entity.LastUpdatedDate;
                            user.CreatedByUser = string.Format("{0} {1}", entity.UserLogin.FirstName, entity.UserLogin.LastName);
                            user.LastUpdatedByUser = string.Format("{0} {1}", entity.UserLogin1.FirstName, entity.UserLogin1.LastName);
                        }

                        const UserPermission allPermission = UserPermission.EditParts | UserPermission.EditUsers;
                        var permission = UserPermission.None;
                        if (entity.Permission.Equals((int)UserPermission.EditParts))
                            permission |= UserPermission.EditParts;
                        if (entity.Permission.Equals((int)UserPermission.EditUsers))
                            permission |= UserPermission.EditUsers;
                        if (entity.Permission.Equals((int)allPermission))
                            permission |= allPermission;
                        user.Permission = permission;

                        result.Add(user);
                    }

                    return new GetDataResponse<IList<UserLoginItem>> { Success = true, Data = result, };
                }
                catch (Exception ex)
                {
                    FileLog.Error("GetAreas", ex);
                    return new GetDataResponse<IList<UserLoginItem>> { Success = false, Error = BusinessLogicError.GetUserFailed };
                }
            }
        }

        public SaveDataResponse<UserLoginItem> InsertUser(SaveDataRequest<UserLoginItem> request)
        {
            using (var adapter = new DataAccessAdapter())
            {
                try
                {
                    EntityQuery<UserLoginEntity> query = _queryFactory.UserLogin.Where(UserLoginFields.Login == request.Data.Login);
                    UserLoginEntity duplicatedUser = adapter.FetchFirst(query);
                    if (duplicatedUser != null)
                        return new SaveDataResponse<UserLoginItem> { Error = BusinessLogicError.DuplicatedUsername, Success = false };

                    var encryptPassword = EncryptionHelper.EncodePassword(request.Data.Password);
                    DateTime dateTimeNow = DateTime.UtcNow;
                    var userEntity = new UserLoginEntity
                    {
                        Login = request.Data.Login,
                        Email = request.Data.Email,
                        Enabled = request.Data.Enabled,
                        Password = encryptPassword,
                        FirstName = request.Data.FirstName,
                        LastName = request.Data.LastName,
                        Permission = (int)request.Data.Permission,
                        LastUpdatedBy = request.Identity.UserLoginId,
                        LastUpdatedDate = dateTimeNow,
                        CreatedBy = request.Identity.UserLoginId,
                        CreatedDate = dateTimeNow,
                    };

                    bool result = adapter.SaveEntity(userEntity);
                    if (!result)
                        return new SaveDataResponse<UserLoginItem> { Success = false, Error = BusinessLogicError.InsertUserFailed };

                    // Get user entity after updated
                    var q = _queryFactory.Create()
                        .Select(() => new
                        {
                            FirstName = UserLoginFields.FirstName.Source("u").ToValue<string>(),
                            LastName = UserLoginFields.LastName.Source("u").ToValue<string>(),
                            Email = UserLoginFields.Email.Source("u").ToValue<string>(),
                            Login = UserLoginFields.Login.Source("u").ToValue<string>(),
                            Enabled = UserLoginFields.Enabled.Source("u").ToValue<Boolean>(),
                            Permission = UserLoginFields.Permission.Source("u").ToValue<Int32>(),
                            LastUpdatedDate = UserLoginFields.LastUpdatedDate.Source("u").ToValue<DateTime>(),
                            CreatedDate = UserLoginFields.CreatedDate.Source("u").ToValue<DateTime>(),
                            UserLoginId = UserLoginFields.UserLoginId.Source("u").ToValue<Int32>(),
                            FirstName1 = (UserLoginFields.FirstName.Source("u1").SetFieldAlias("FistName1")).ToValue<string>(),
                            LastName1 = (UserLoginFields.LastName.Source("u1").SetFieldAlias("LastName1")).ToValue<string>(),
                        })
                        .From(_queryFactory.UserLogin.InnerJoin(UserLoginEntity.Relations.UserLoginEntityUsingUserLoginIdLastUpdatedBy, "u", "u1"))
                        .Where(UserLoginFields.Login.Source("u") == request.Data.Login);

                    var ret = adapter.FetchQuery(q);
                    if (ret.Any())
                    {
                        string user = string.Format(FormatString.NameFormat, ret[0].FirstName1, ret[0].LastName1);
                        return new SaveDataResponse<UserLoginItem>
                        {
                            Success = true,
                            Data = new UserLoginItem
                            {
                                FirstName = ret[0].FirstName,
                                LastName = ret[0].LastName,
                                Email = ret[0].Email,
                                Login = ret[0].Login,
                                Enabled = ret[0].Enabled,
                                LastUpdatedDate = ret[0].LastUpdatedDate,
                                CreatedDate = ret[0].CreatedDate,
                                LastUpdatedByUser = user,
                                UserLoginId = ret[0].UserLoginId,
                                CreatedByUser = user,
                                Permission = (UserPermission)ret[0].Permission
                            }
                        };
                    }
                    return new SaveDataResponse<UserLoginItem> { Success = false, Error = BusinessLogicError.InsertUserFailed };
                }
                catch (Exception ex)
                {
                    FileLog.Error("InsertUser", ex);
                    return new SaveDataResponse<UserLoginItem> { Success = false, Error = BusinessLogicError.InsertUserFailed };
                }
            }
        }

        public SaveDataResponse<UserLoginItem> UpdateUser(SaveDataRequest<UserLoginItem> request)
        {
            using (var adapter = new DataAccessAdapter())
            {
                try
                {
                    EntityQuery<UserLoginEntity> query = _queryFactory.UserLogin.Where(UserLoginFields.UserLoginId == request.Data.UserLoginId);

                    UserLoginEntity user = adapter.FetchFirst(query);
                    if (user == null)
                        return new SaveDataResponse<UserLoginItem> { Error = BusinessLogicError.UserDoesNotExist, Success = false };

                    user.FirstName = request.Data.FirstName;
                    user.LastName = request.Data.LastName;
                    user.Email = request.Data.Email;
                    user.Login = request.Data.Login;
                    user.Permission = (int)request.Data.Permission;
                    user.Enabled = request.Data.Enabled;
                    user.LastUpdatedBy = request.Identity.UserLoginId;
                    user.LastUpdatedDate = DateTime.UtcNow;
                    if (!string.IsNullOrEmpty(request.Data.Password))
                        user.Password = EncryptionHelper.EncodePassword(request.Data.Password);

                    var result = adapter.SaveEntity(user);

                    if (!result)
                        return new SaveDataResponse<UserLoginItem> { Success = false, Error = BusinessLogicError.UpdateUserFailed };

                    // Get user entity after updated
                    var q = _queryFactory.Create()
                        .Select(() => new
                        {
                            FirstName = UserLoginFields.FirstName.Source("u").ToValue<string>(),
                            LastName = UserLoginFields.LastName.Source("u").ToValue<string>(),
                            Email = UserLoginFields.Email.Source("u").ToValue<string>(),
                            Login = UserLoginFields.Login.Source("u").ToValue<string>(),
                            Enabled = UserLoginFields.Enabled.Source("u").ToValue<Boolean>(),
                            Permission = UserLoginFields.Permission.Source("u").ToValue<Int32>(),
                            LastUpdatedDate = UserLoginFields.LastUpdatedDate.Source("u").ToValue<DateTime>(),
                            CreatedDate = UserLoginFields.CreatedDate.Source("u").ToValue<DateTime>(),
                            UserLoginId = UserLoginFields.UserLoginId.Source("u").ToValue<Int32>(),
                            FirstName1 = (UserLoginFields.FirstName.Source("u1").SetFieldAlias("FistName1")).ToValue<string>(),
                            LastName1 = (UserLoginFields.LastName.Source("u1").SetFieldAlias("LastName1")).ToValue<string>(),
                        })
                        .From(_queryFactory.UserLogin.InnerJoin(UserLoginEntity.Relations.UserLoginEntityUsingUserLoginIdLastUpdatedBy, "u", "u1"))
                        .Where(UserLoginFields.UserLoginId.Source("u") == request.Data.UserLoginId);

                    var val = adapter.FetchQuery(q).FirstOrDefault();
                    if (val == null)
                        return new SaveDataResponse<UserLoginItem> { Success = false, Error = BusinessLogicError.UpdateUserFailed };

                    return new SaveDataResponse<UserLoginItem>
                    {
                        Success = true,
                        Data = new UserLoginItem
                        {
                            FirstName = val.FirstName,
                            LastName = val.LastName,
                            Email = val.Email,
                            Login = val.Login,
                            Permission = (UserPermission)val.Permission,
                            UserLoginId = val.UserLoginId,
                            Enabled = val.Enabled,
                            LastUpdatedByUser = string.Format(FormatString.NameFormat, val.FirstName1, val.LastName1),
                            LastUpdatedDate = val.LastUpdatedDate,
                        }
                    };
                }
                catch (Exception ex)
                {
                    FileLog.Error("UpdateUser", ex);
                    return new SaveDataResponse<UserLoginItem> { Success = false, Error = BusinessLogicError.UpdateUserFailed };
                }
            }
        }
    }
}
